/****************************************************************************
 * Copyright (c) 2015 - 2022 liangxiegame UNDER MIT License
 * 
 * https://qframework.cn
 * https://github.com/liangxiegame/QFramework
 * https://gitee.com/liangxiegame/QFramework
 ****************************************************************************/

using System;
using UniRx;

namespace QFramework
{
    public class UniRxAction<T> : IAction
    {
        private Func<IObservable<T>> mObservableGetter;

        private UniRxAction()
        {
        }

        private static SimpleObjectPool<UniRxAction<T>> mPool =
            new SimpleObjectPool<UniRxAction<T>>(() => new UniRxAction<T>(), null, 3);

        public static UniRxAction<T> Allocate(Func<IObservable<T>> observableGetter)
        {
            var uniRxAction = mPool.Allocate();
            uniRxAction.ActionID = ActionKit.ID_GENERATOR++;
            uniRxAction.Reset();
            uniRxAction.Deinited = false;
            uniRxAction.mObservableGetter = observableGetter;
            return uniRxAction;
        }

        public bool Paused { get; set; }

        public void Reset()
        {
            Status = ActionStatus.NotStart;
            Paused = false;
        }

        public void Deinit()
        {
            if (!Deinited)
            {
                Deinited = true;

                if (mExecutingObservable != null)
                {
                    mExecutingObservable.Dispose();
                    mExecutingObservable = null;
                }

                mPool.Recycle(this);
            }
        }

        public ulong ActionID { get; set; }
        public ActionStatus Status { get; set; }

        private IDisposable mExecutingObservable;

        public void OnStart()
        {
            mExecutingObservable = mObservableGetter().Subscribe(_ => this.Finish());
        }

        public void OnExecute(float dt)
        {
        }

        public void OnFinish()
        {
            mExecutingObservable = null;
        }

        public bool Deinited { get; set; }
    }

    public static class ActionKitUniRxExtension
    {
        public static IAction ToAction<T>(this IObservable<T> self)
        {
            return UniRxAction<T>.Allocate(() => self);
        }

        public static ISequence UniRx<T>(this ISequence self, Func<IObservable<T>> observableGetter)
        {
            return self.Append(UniRxAction<T>.Allocate(observableGetter));
        }
    }
}